home *** CD-ROM | disk | FTP | other *** search
- /*
- * Objects-in-C object manager
- *
- * Copyright © John Wainwright 1988
- *
- */
-
- #include <stdio.h>
- #include "oic.h"
- #include "generics.h"
- #include "varargs.h"
-
- #define CHECK_OBJS 1 /* turn on or off object checking */
- /* #define IGNORE_NULL_OBJS 1 /* ignore generics on NULL objects */
-
- class currentClass; /* class of currently exec'ing method */
- int currentClassIndex; /* index of current class */
- GenericTable *currentGeneric; /* current generic method table */
- GenericTable *generics; /* linked list of generic tables */
-
- static int trace; /* trace flag */
- static class trace_class; /* class for class constrained trace */
- static object trace_obj; /* obj for obj constrained trace */
- static int gen_level; /* generic nest level */
- static int class_index; /* class index generator */
-
- /*---------------------------- Class Maker ----------------------------- */
-
- /*
- * create a new class.
- */
- class
- NewClass(ivsize, cvsize, name, va_alist)
- int ivsize, cvsize;
- char *name;
- va_dcl
- {
- va_list pvar;
- register class c;
- register class superclass;
- register classlist **clp;
- register int cvallocz;
- register int nsupers;
- int ivoffset, cvoffset;
- char *strcpy(), *salloc();
-
- c = talloc(struct class_struct);
- c->c_classtag = Class;
- c->c_index = ++class_index; /* origin 1 */
- c->c_name = strcpy(salloc(strlen(name) + 1), name);
- c->c_lclivsize = (ivsize + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
- c->c_lclcvsize = (cvsize + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
- c->c_next = classes;
- classes = c;
-
- /* build the supers list */
-
- c->c_ivsize = c->c_cvsize = 0;
- clp = &c->c_superclasses;
- va_start(pvar);
- for (nsupers = 0; (superclass = va_arg(pvar, class)) != END; )
- {
- if (superclass->c_classtag != Class)
- gprintf(error, "NewClass (%s): super %d is not a class\n", name, nsupers+1);
- *clp = talloc(classlist);
- (*clp)->cl_class = superclass;
- clp = &(*clp)->cl_next;
-
- c->c_ivsize += superclass->c_ivsize;
- c->c_cvsize += superclass->c_cvsize;
- c->c_flags |= (superclass->c_flags & C_HASCLASSMETHODS);
- nsupers += 1;
- }
-
- if (nsupers == 0) /* inherit, at least, from Object */
- {
- *clp = talloc(classlist);
- (*clp)->cl_class = Object;
- clp = &(*clp)->cl_next;
- }
-
- *clp = END;
-
- /* construct the IV & CV offset tables */
-
- c->c_ivoffsets = (int *)scalloc(sizeof(int) * (c->c_index + 1));
- c->c_ivoffsets[c->c_index] = c->c_ivsize + sizeof(object);
-
- if ((c->c_flags & C_HASCLASSMETHODS) | /* CV offsets only if used */
- (c->c_cvsize + c->c_lclcvsize) != 0)
- {
- c->c_cvoffsets = (int *)scalloc(sizeof(int) * (c->c_index + 1));
- c->c_cvoffsets[c->c_index] = c->c_cvsize + sizeof(object);
- }
-
- ivoffset = cvoffset = sizeof(object);
- buildOffsetTables(c, c->c_superclasses, &ivoffset, &cvoffset);
-
- /* compute complete object's allocation size */
-
- c->c_ivsize += c->c_lclivsize;
- c->c_allocz = c->c_ivsize + sizeof(object);
-
- /* allocate any class variable structure for this class */
-
- c->c_cvsize += c->c_lclcvsize;
- if (c->c_cvsize)
- c->c_classvars = scalloc(c->c_cvsize + sizeof(object));
- else
- c->c_classvars = 0;
-
- return c;
- }
-
- /* construct the IV & CV offset tables */
-
- static
- buildOffsetTables(c, cl, ivoffset, cvoffset)
- register class c;
- register classlist *cl;
- register int *ivoffset, *cvoffset;
- {
- register class sc;
-
- for (; cl != END; cl = cl->cl_next)
- if ((sc = cl->cl_class) != NULL) /* ignore bootstrapping Object */
- {
- buildOffsetTables(c, sc->c_superclasses, ivoffset, cvoffset);
- if (c->c_ivoffsets[sc->c_index] == 0)
- c->c_ivoffsets[sc->c_index] = *ivoffset;
- if (c->c_cvoffsets != NULL)
- if (c->c_cvoffsets[sc->c_index] == 0)
- c->c_cvoffsets[sc->c_index] = *cvoffset;
- *ivoffset += sc->c_lclivsize;
- *cvoffset += sc->c_lclcvsize;
- }
- }
-
- int
- IsA(obj, c)
- register object obj;
- register class c;
- {
- return (c == *obj);
- }
-
- int
- SubClassOf(c1, c2)
- register class c1, c2;
- {
- register classlist *cl;
-
- if (c1 == c2)
- return 1;
- for (cl = c1->c_superclasses; cl != END; cl = cl->cl_next)
- if (SubClassOf(cl->cl_class, c2))
- return 1;
-
- return 0;
- }
-
- int
- IsAKindOf(obj, c)
- register object obj;
- register class c;
- {
- return SubClassOf(ClassOf(obj), c);
- }
-
- char *
- ClassNameOf(obj)
- object obj;
- {
- return (*obj)->c_name;
- }
-
- int
- IsObj(obj) /* attempts to tell if this is a valid object */
- object obj;
- {
- return (obj != 0 &&
- ((long)obj & ~0x1L) == (long)obj &&
- ((long)obj & 0xFFFFFF) <= (long)ApplLimit &&
- ClassOf(obj) != 0 &&
- ((long)ClassOf(obj) & ~0x1L) == (long)ClassOf(obj) &&
- ((long)ClassOf(obj) & 0xFFFFFF) <= (long)ApplLimit &&
- ClassOf(obj)->c_classtag == Class);
- }
-
- InitOIC()
- {
- /*
- * Bootstrap the Class system...
- * Make initial classes and hand patch those bits that assume
- * they already exist.
- */
-
- Object = NULL; classes = NULL; generics = NULL;
- Object = NewClass(0, 0, "Object", END);
- Class = NewClass(sizeof(struct class_struct), 0, "Class", END);
- Class->c_classtag = Class;
- Object->c_classtag = Class;
- free(Object->c_superclasses);
- Object->c_superclasses = END;
- InitObject();
- InitClass();
- }
-
- /* ------------------------ Method Tables Manager --------------------- */
-
- /*
- * add methods for a given class to generic function method tables.
- * The class is given followed by a NULL-terminated list of pairs
- * of methodTable & local function addresses.
- */
- AddMethods(c, va_alist)
- class c;
- va_dcl
- {
- va_list pvar;
- register GenericTable *gen;
-
- for (va_start(pvar); (gen = va_arg(pvar, GenericTable *)) != END; )
- {
- AddMethod(c, &gen->gen_mtables[0], (object (*)())va_arg(pvar, char *));
- if (gen->gen_next == UNLINKED)
- {
- gen->gen_next = generics;
- generics = gen;
- }
- }
- }
-
- /*
- * add class methods for a given class to generic function method tables.
- */
- AddClassMethods(c, va_alist)
- class c;
- va_dcl
- {
- va_list pvar;
- register GenericTable *gen;
- register MethTable *mth;
-
- for (va_start(pvar); (gen = va_arg(pvar, GenericTable *)) != END; )
- {
- AddMethod(c, &gen->gen_mtables[CLASS], (object (*)())va_arg(pvar, char *));
- if (gen->gen_next == UNLINKED)
- {
- gen->gen_next = generics;
- generics = gen;
- }
- }
-
- c->c_flags |= C_HASCLASSMETHODS;
- }
-
- /*
- * add a method for a given class to generic function method tables.
- */
- AddMethod(c, mth, func)
- class c;
- register MethTable *mth;
- object (*func)();
- {
- if (mth->mth_meths == 0)
- {
- mth->mth_minClass = c->c_index;
- mth->mth_maxClass = c->c_index;
- mth->mth_meths = (Method *)scalloc(sizeof(Method));
- }
- else if (c->c_index < mth->mth_minClass)
- {
- reallocMethTable(mth, c->c_index - mth->mth_minClass);
- mth->mth_minClass = c->c_index;
- }
- else if (c->c_index > mth->mth_maxClass)
- {
- reallocMethTable(mth, c->c_index - mth->mth_maxClass);
- mth->mth_maxClass = c->c_index;
- }
-
- mth->mth_meths[c->c_index - mth->mth_minClass].mf_func = func;
- mth->mth_meths[c->c_index - mth->mth_minClass].mf_from = c;
- }
-
- /*
- * extend a generic function's method function table.
- * -ve adjustment => add to front, +ve add to end.
- */
- static
- reallocMethTable(mth, adjustment)
- register MethTable *mth;
- register int adjustment;
- {
- register int i, n;
- register Method *funcs;
-
- n = mth->mth_maxClass - mth->mth_minClass + 1;
- funcs = (Method *)scalloc(sizeof(Method) * (n + abs(adjustment)));
-
- for (i = 0; i < n; i++)
- funcs[i - ((adjustment < 0) ? adjustment : 0)] = mth->mth_meths[i];
-
- if (mth->mth_meths)
- free(mth->mth_meths);
- mth->mth_meths = funcs;
- }
-
- char *
- GenericName(gen)
- register GenericTable *gen;
- {
- return gen->gen_name;
- }
-
- /*------------------------ Method Dispatcher -------------------------*/
-
- /* find the method's function
- *
- * does a breadth-first search of the superclass DAG looking for a
- * method function. Caches the function in the local class if inherited.
- */
- static object
- ((*getMethod(c, mth))())
- register class c;
- register MethTable *mth;
- {
- register classlist *cl;
- register int i;
- register object (*func)();
- register Method *mf, *smf;
-
- /*
- * check this class
- */
- i = c->c_index - mth->mth_minClass;
- mf = &mth->mth_meths[i];
- if (i >= 0 && c->c_index <= mth->mth_maxClass &&
- (func = mf->mf_func) != NULL)
- {
- currentClass = mf->mf_from;
- return func;
- }
-
- /*
- * else, check immediate supers in breadth-first search
- */
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- {
- i = cl->cl_class->c_index - mth->mth_minClass;
- smf = &mth->mth_meths[i];
- if (i >= 0 && cl->cl_class->c_index <= mth->mth_maxClass &&
- (func = smf->mf_func) != NULL)
- {
- /*
- * inherited, cache it in the local class's method table
- */
- AddMethod(c, mth, func);
- currentClass =
- mth->mth_meths[cl->cl_class->c_index - mth->mth_minClass].mf_from;
- mth->mth_meths[c->c_index - mth->mth_minClass].mf_from =
- currentClass;
- return func;
- }
- }
-
- /*
- * else, recurse down the superclass DAG
- */
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- if ((func = getMethod(cl->cl_class, mth)) != NULL)
- {
- AddMethod(c, mth, func);
- mth->mth_meths[c->c_index - mth->mth_minClass].mf_from =
- currentClass;
- return func;
- }
-
- return NULL;
- }
-
- /*
- * dispatch a generic's method function.
- * also keeps track of the class in which the current method was found.
- */
- object
- Dispatch(gen, obj, args)
- register GenericTable *gen;
- register object obj;
- char *args;
- {
- register object (*func)();
- class saveCurrentClass;
- GenericTable *saveCurrentGeneric;
-
- #ifdef IGNORE_NULL_OBJS
- if (obj == NULL)
- return NULL;
- #endif
-
- #ifdef CHECK_OBJS
- if (!IsObj(obj))
- {
- gprintf(error, "** method (%s) to non-object (%lx)\n", gen->gen_name, obj);
- return NULL;
- }
- #endif
-
- saveCurrentClass = currentClass;
- saveCurrentGeneric = currentGeneric;
- if ((func = getMethod(*obj, &gen->gen_mtables[0])) != NULL)
- {
- if (trace)
- traceGeneric(gen, obj);
- gen_level += 1;
- currentGeneric = gen;
-
- obj = (*func)(obj, &((char *)obj)[ClassOf(obj)->c_ivoffsets[currentClass->c_index]], args);
-
- gen_level -= 1;
- currentClass = saveCurrentClass;
- currentGeneric = saveCurrentGeneric;
-
- return obj;
- }
-
- return cantDo(obj, gen, args);
- }
-
- /*
- * dispatch a generic's class method function.
- *
- * given the class method function table. calls the function with class
- * and local class variable structure as the 1st 2 args.
- *
- * if a class method is not found, attempts to invoke the generic as a
- * normal method on class 'class'.
- *
- * this function, which could have been integrated with 'Method', is a
- * separate function in the interests of efficiency.
- */
- object
- ClassDispatch(gen, c, args)
- register GenericTable *gen;
- register class c;
- char *args;
- {
- register object (*func)();
- register object obj;
- class saveCurrentClass;
- GenericTable *saveCurrentGeneric;
-
- #ifdef IGNORE_NULL_OBJS
- if (obj == NULL)
- return NULL;
- #endif
-
- #ifdef CHECK_OBJS
- if (!(IsObj(c) && c->c_classtag == Class))
- {
- gprintf(error, "** class method (%s) to non-class (%lx)\n", gen->gen_name, c);
- return NULL;
- }
- #endif
-
- saveCurrentClass = currentClass;
- saveCurrentGeneric = currentGeneric;
- if ((func = getMethod(c, &gen->gen_mtables[CLASS])) != NULL)
- {
- if (trace)
- traceClassGeneric(gen, c);
- gen_level += 1;
- currentGeneric = gen;
-
- obj = (*func)(c, &(c->c_classvars)[c->c_cvoffsets[currentClass->c_index]], args);
-
- gen_level -= 1;
- currentClass = saveCurrentClass;
- currentGeneric = saveCurrentGeneric;
-
- return obj;
- }
- else
- return Dispatch(gen, c, args); /* otherwise give it to class Class */
-
- }
-
- /*
- * this function applies the given generic (as its methodtable) to the
- * object and arg pointer given. Often used by "cantDo" to pass on the
- * generic to some other object.
- */
- object
- ApplyGeneric(gen, obj, args)
- GenericTable *gen;
- register object obj;
- char *args;
- {
- return
- (ClassOf(obj) == Class) ?
- ClassDispatch(gen, obj, args)
- :
- Dispatch(gen, obj, args);
- }
-
- int
- CanYouDo(obj, gen) /* can object handle generic ? */
- register object obj;
- register generic gen;
- {
- if (ClassOf(obj) == Class)
- return getMethod(ClassOf(obj), &gen->gen_mtables[CLASS]) != NULL;
- return getMethod(ClassOf(obj), &gen->gen_mtables[0]) != NULL;
- }
-
- /*
- * called by Super to find the method definition next up the superclass
- * DAG from the current method's class.
- *
- * does a breadth-first search of the superclass DAG looking for the
- * method function inherited from the supers further than 'currentClass'.
- *
- * this function, a slight variant of 'getMethod', is a
- * separate function in the interests of efficiency.
- */
- static object
- ((*getSuperMethod(c, mth, beyond))())
- register class c;
- register MethTable *mth;
- int beyond;
- {
- register classlist *cl;
- register int i;
- register object (*func)();
- register Method *mf, *smf;
-
- /*
- * check this class
- */
- i = c->c_index - mth->mth_minClass;
- mf = &mth->mth_meths[i];
-
- if (mf->mf_from == currentClass)
- beyond = 1;
-
- if (beyond &&
- mf->mf_from != currentClass && /* ignore current method's class */
- i >= 0 && c->c_index <= mth->mth_maxClass &&
- (func = mf->mf_func) != NULL)
- {
- currentClass = mf->mf_from;
- return func;
- }
-
- /*
- * else, check immediate supers in breadth-first search
- */
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- {
- i = cl->cl_class->c_index - mth->mth_minClass;
- smf = &mth->mth_meths[i];
-
- if (smf->mf_from == currentClass)
- beyond = 1;
-
- if (beyond &&
- smf->mf_from != currentClass &&
- i >= 0 && cl->cl_class->c_index <= mth->mth_maxClass &&
- (func = smf->mf_func) != NULL)
- {
- currentClass = smf->mf_from;
- return func;
- }
- }
-
- /*
- * else, recurse down the superclass DAG
- */
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- if ((func = getSuperMethod(cl->cl_class, mth, beyond)) != NULL)
- return func;
-
- return NULL;
- }
-
- object
- Super(obj, args)
- object obj;
- char *args;
- {
- register object (*func)();
- class saveCurrentClass;
-
- #ifdef CHECK_OBJS
- if (!IsObj(obj))
- {
- gprintf(error, "** super method (%s) on non-object (%lx)\n", currentGeneric->gen_name, obj);
- return NULL;
- }
- #endif
-
- saveCurrentClass = currentClass;
- if ((func = getSuperMethod(*obj, ¤tGeneric->gen_mtables[0], 0)) != NULL)
- {
- if (trace)
- traceSuperGeneric(currentGeneric, obj);
- gen_level += 1;
-
- obj = (*func)(obj, &((char *)obj)[ClassOf(obj)->c_ivoffsets[currentClass->c_index]], &args);
-
- gen_level -= 1;
- currentClass = saveCurrentClass;
-
- return obj;
- }
- else
- return cantDo(obj, currentGeneric, &args);
- }
-
- /*
- * Identical to 'Super', above, except that a pointer to the argument
- * list is given instead of them being in place.
- *
- * This allows methods to easily pass their arguments up to the super
- * they are invoking (e.g., see 'new' in IndexMixin).
- *
- * Like other variant functions, it is a separate function in the
- * interests of efficiency.
- */
- object
- SuperPassArgs(obj, argp)
- object obj;
- char **argp;
- {
- register object (*func)();
- class saveCurrentClass;
-
- #ifdef CHECK_OBJS
- if (!IsObj(obj))
- {
- gprintf(error, "** super method (%s) on non-object (%lx)\n", currentGeneric->gen_name, obj);
- return NULL;
- }
- #endif
-
- saveCurrentClass = currentClass;
- if ((func = getSuperMethod(*obj, ¤tGeneric->gen_mtables[0], 0)) != NULL)
- {
- if (trace)
- traceSuperGeneric(currentGeneric, obj);
- gen_level += 1;
-
- obj = (*func)(obj, &((char *)obj)[ClassOf(obj)->c_ivoffsets[currentClass->c_index]], argp);
-
- gen_level -= 1;
- currentClass = saveCurrentClass;
-
- return obj;
- }
- else
- return cantDo(obj, currentGeneric, argp);
- }
-
- /*
- * invokes super from given inherited class.
- */
- object
- SuperFrom(c, obj, args)
- class c;
- object obj;
- char *args;
- {
- register object (*func)();
- class saveCurrentClass;
-
- #ifdef CHECK_OBJS
- if (!IsObj(obj))
- {
- gprintf(error, "** super method (%s) on non-object (%lx)\n", currentGeneric->gen_name, obj);
- return NULL;
- }
- #endif
-
- saveCurrentClass = currentClass;
- if ((func = getMethod(c, ¤tGeneric->gen_mtables[0], 0)) != NULL)
- {
- if (trace)
- traceSuperGeneric(currentGeneric, obj);
- gen_level += 1;
-
- obj = (*func)(obj, &((char *)obj)[ClassOf(obj)->c_ivoffsets[currentClass->c_index]], &args);
-
- gen_level -= 1;
- currentClass = saveCurrentClass;
-
- return obj;
- }
- else
- return cantDo(obj, currentGeneric, &args);
- }
-
- /*---------------------------- Object Maker -----------------------------*/
-
- /*
- * creates a new instance of the given class. Inits all instance vars to
- * zero, and sends 'new' to it.
- */
- object
- New(c, args)
- register class c;
- char *args;
- {
- register object obj;
- register char *p;
-
- obj = (object)scalloc(c->c_allocz);
- *obj = c;
- Dispatch(newGeneric, obj, &args); /* send it the 'new' message */
-
- return obj;
- }
-
- int
- SizeOf(obj)
- object obj;
- {
- return ClassOf(obj)->c_allocz;
- }
-
- static int tracing = 0;
-
- static
- traceGeneric(gen, obj)
- GenericTable *gen;
- object obj;
- {
- if (!tracing &&
- trace_class == NULL || *obj == trace_class &&
- trace_obj == NULL || obj == trace_obj)
- {
- tracing = 1;
- gprintf(error, "%.*s%s ", gen_level,
- gen_level ? ".............." : "", GenericName(gen));
- if (ClassOf(obj) != currentClass)
- gprintf(error, "(from %s) ", currentClass->c_name);
- gprintf(error, "on %s @%lx\n", ClassNameOf(obj), obj);
- tracing = 0;
- }
- }
-
- static
- traceClassGeneric(gen, c)
- GenericTable *gen;
- object c;
- {
- if (!tracing &&
- trace_class == NULL || ClassOf(c) == trace_class &&
- trace_obj == NULL || c == trace_obj)
- {
- tracing = 1;
- gprintf(error, "%.*s%s ", gen_level,
- gen_level ? ".............." : "", GenericName(gen));
- if ((class)c != currentClass)
- gprintf(error, "(from %s) ", currentClass->c_name);
- gprintf(error, "on class %s @%lx\n", ((class)c)->c_name, c);
- tracing = 0;
- }
- }
-
- static
- traceSuperGeneric(gen, obj)
- GenericTable *gen;
- object obj;
- {
- if (!tracing &&
- trace_class == NULL || *obj == trace_class &&
- trace_obj == NULL || obj == trace_obj)
- {
- tracing = 1;
- gprintf(error, "%.*ssuper %s ", gen_level,
- gen_level ? ".........." : "", GenericName(gen));
- if (ClassOf(obj) != currentClass)
- gprintf(error, "(from %s) ", currentClass->c_name);
- gprintf(error, "on %s @%lx\n", ClassNameOf(obj), obj);
- tracing = 0;
- }
- }
-
- TraceOn()
- {
- trace = 1;
- }
-
- TraceOff()
- {
- trace = 0;
- trace_obj = NULL;
- trace_class = NULL;
- }
-
- TraceObj(obj)
- object obj;
- {
- trace = 1;
- trace_obj = obj;
- }
-
- TraceClass(c)
- class c;
- {
- trace = 1;
- trace_class = c;
- }
-
- dumpClass(c)
- register class c;
- {
- register classlist *cl;
-
- gprintf(error, "Class \"%s\" :\n", c->c_name);
- gprintf(error, " supers : (");
- for (cl = c->c_superclasses; cl != END; cl = cl->cl_next)
- gprintf(error, "%s%s", cl->cl_class->c_name, (cl->cl_next) ? "," : "");
- gprintf(error, ")\n index %d\n cv\'s %lx\n", c->c_index,
- c->c_classvars);
- }
-
- object
- key_arg(arglist, key, default_arg)
- register keyword_args arglist;
- int key;
- object default_arg;
- {
- for (; *(int *)arglist != key && *(int *)arglist != 0; arglist += sizeof(int) + sizeof(long))
- ;
- if (*(int *)arglist == 0)
- return default_arg;
- else
- return *(object *)(arglist + sizeof(int));
- }
-